package com.berchen.volatile关键字;

/**
 * 测试内存可见性
 */
public class MemoryVisibility {

    /**
     * 程序运行会在每一个线程中都开辟一块自己的缓存，同时有一块主存。
     * 所有的数据交换都在缓存中。
     * tb线程在自己缓存中将flag=true。
     * 但是tb线程还没有将flag更改的值更新到主存中。这时候main线程就获取到主存中的值flag=false。
     * while(true)的执行效率很高。所以不会给main线程去读取主存中新的flag=true的数据。所以程序就一直会卡在while循环这里。
     * <p>
     * <p>
     * 解决办法：
     * 1、加锁。加了线程锁就会去刷新内存的数据。这样main线程就可以读取到flag=true的数据了。
     * synchronized (tb) {
     * if (tb.isFlag()) {
     * System.out.println("flag" + tb.isFlag());
     * break;
     * }
     * }
     * 加锁的问题：
     * 加锁导致每一个线程都会去判断锁，如果有线程不满足。就会阻塞，只有等到下一次CPU执行该线程继续判断。这就造成效率低下。
     * 2、volatile关键字：保证多个线程访问共享资源的时候，可以保证内存中的数据是可见的。
     *  (1)相较于synchronized，volatile是一种较为轻量级的同步策略。
     * (2)volatile不具备互斥性。synchronized具有互斥性。互斥性：一个线程访问共享资源，其他的线程只有等待。
     * (3)volatile不能保证变量的原子性。原子性：是一个不可分割的整体。
     */
    public static void main(String[] args) {

        RunableImpl tb = new RunableImpl();
        new Thread(tb).start();  // 启动下面自定义的线程

        // main的主线程
        while (true) {

            if (tb.isFlag()) {

                System.out.println("flag" + tb.isFlag());
                break;
            }
        }
    }
}

class RunableImpl implements Runnable {

    private volatile boolean flag = false;  // 共享数据

    @Override
    public void run() {

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println("flag已经改变");
    }

    public boolean ifFlag() {

        return flag;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
